#ifndef ASTARSEARCH_H
#define ASTARSEARCH_H

#include <QObject>

class AStarSearchNode : public QObject {
public:
    AStarSearchNode(QObject *parent = NULL);
    virtual bool operator==(const AStarSearchNode& other) const = 0;

    virtual float heuristicEstimateOfDistance(const AStarSearchNode& other) const = 0;
    virtual float distanceTo(const AStarSearchNode& other) const = 0;
    virtual void neighborNodes(QList<AStarSearchNode*>& neighbors) const = 0;
    virtual QString nodeInfo() const = 0;

    void setG(float g);
    void setH(float h);
    void setF(float f);
    const AStarSearchNode* cameFrom() const;
    void setCameFrom(const AStarSearchNode* cameFrom);
    float g() const;
    float h() const;
    float f() const;
    bool operator<(const AStarSearchNode& other) const;
    static bool lessThan(const AStarSearchNode* s1, const AStarSearchNode* s2);

private:
    float m_g;
    float m_h;
    float m_f;
    const AStarSearchNode* m_came_from;
};

class AStarSearch : public QObject
{
    Q_OBJECT
public:
    explicit AStarSearch(QObject *parent = 0);
    ~AStarSearch();

    /**
     * Start a search, if search is onging, do nothing
     * NOTE, after call this function, original searched path is not available anymore
     * @param start The start point
     * @param goal The end point
     * @param pathToGoal The found path to goal, if count is 0, means no path found
     * @return true for success, false for already searching
     */
    bool search(AStarSearchNode& start,
                AStarSearchNode& goal,
                QList<AStarSearchNode*>& pathToGoal);

    bool seaching();
signals:

public slots:

private:
    bool pathTo(const AStarSearchNode& currentNode,
                const AStarSearchNode& targetNode,
                QList<AStarSearchNode*>& path);
    void freeNodes();
    bool nodeContainedInList(const QList<AStarSearchNode*>& list,
                             const AStarSearchNode* node);

private:
    QList<AStarSearchNode*> m_nodes;
    bool m_searching;
};

#endif // ASTARSEARCH_H
